/*
 * @Descripttion: 多边形按钮点击检测组件
 * @Author: jindekun
 * @Date: 2022-07-12 17:27:05
 */

import * as cc from "cc";
import { threadId } from "worker_threads";
import { C } from "../../utils/ClickableMgr";
import { GeometryUtils } from "../../utils/GeometryUtils";

/**多边形按钮初始化参数 */
export interface PolygonButtonParams {
    /**默认点击音效 */
    clickAudio?: string,
    /**是否忽略点击音效 */
    ignoreClickAudio?: boolean,
    /**正多边形数据*/
    regularPolygon?: {
        /**正多边形半径 */
        radius?: number,
        /**正多边形顶点数量 */
        pointCount?: number,
        /**多边形区域距离坐标原点偏移 */
        offset?: cc.Vec2,
    },
    /**多边形定点位置信息（局部坐标，至少3个点） */
    points?: cc.Vec2[],
    /**是否显示调试框 */
    showDebugPolygon: boolean,
    /**是否播放点击动画,默认播放 */
    anim?: boolean,
    /**是否检查点击过快,默认检查 */
    checkClickAble?: boolean
}
const PolygonButtonDebugNode = "PolygonButtonDebugNode";
const { ccclass, property, executeInEditMode, menu } = cc._decorator;
@ccclass("ButtonPolygon")
@executeInEditMode()
@menu("扩展组件/ButtonPolygon")
export default class ButtonPolygon extends cc.Component {

    @property({ displayName: "是否显示调试框" })
    showDebugPolygon: boolean = false;
    @property({ displayName: "是否播放点击缩放动画" })
    anim: boolean = true;
    @property({ displayName: "是否检查点击过快" })
    checkClickAble: boolean = false;
    @property({ displayName: "是否为正多边形" })
    isRegularPolygon: boolean = true;
    @property({ type: cc.CCInteger, displayName: "正多边形顶点数量", visible() { return this.isRegularPolygon } })
    pointCount: number = 0;
    @property({ type: cc.CCFloat, displayName: "正多边形半径", visible() { return this.isRegularPolygon } })
    radius: number = 0;
    @property({ displayName: "坐标偏移", tooltip: "多边形区域距离坐标原点偏移", visible() { return this.isRegularPolygon } })
    offset: cc.Vec2 = cc.v2(0,0);
    @property({ type: [cc.Vec2], tooltip: "多边形定点位置信息（局部坐标，至少3个点）", visible() { return !this.isRegularPolygon } })
    points: Array<cc.Vec2> = [];

    private uiTrans: cc.UITransform = null;

    private target:any = null;
    /**点击多边形区域内事件回调 */
    private clickListener: (ev: cc.EventTouch) => void = null;
    private isMove: boolean = false;
    private _originalHitTest: (point, listener) => boolean = null;

    onLoad() {
        this.uiTrans = this.node.getComponent(cc.UITransform);
        this._originalHitTest = this.uiTrans.hitTest.bind(this.uiTrans);
        this.uiTrans.hitTest = this._hitTest.bind(this);
        if (this.isRegularPolygon) {
            this.calcPoints();
        }
        this.clearPolygonShow();

        this.anim && this.addButtonComponent();
    }

    resetInEditor() {
        if (this.isRegularPolygon) {
            this.calcPoints();
        }

        //编辑器模式下绘制多边形渲染
        this.showPolygon();
    
    }

    start() {

        if (this.showDebugPolygon) {
            //编辑器模式下绘制多边形渲染
            this.showPolygon();
        }

        this.node.on(cc.Node.EventType.TOUCH_START, this.onClickStart, this);
        this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onClickMove, this);
        this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onClickCancel, this);
        this.node.on(cc.Node.EventType.TOUCH_END, this.onClickEnd, this);

    }

    onDestroy() {
        this.node.off(cc.Node.EventType.TOUCH_START, this.onClickStart, this);
        this.node.off(cc.Node.EventType.TOUCH_MOVE, this.onClickMove, this);
        this.node.off(cc.Node.EventType.TOUCH_CANCEL, this.onClickCancel, this);
        this.node.off(cc.Node.EventType.TOUCH_END, this.onClickEnd, this);
    }

    /**
     * @desc 注册点击事件
     */
    public init(params: PolygonButtonParams) {
        this.anim = params.anim === false ? false : true;
        this.checkClickAble = params.checkClickAble === false ? false : true;
        this.showDebugPolygon = params.showDebugPolygon ? params.showDebugPolygon : this.showDebugPolygon;
        this.points = params.points ? params.points : this.points;
        const regularPolygon = params.regularPolygon;
        if (!!regularPolygon) {
            this.radius = regularPolygon.radius ? regularPolygon.radius : this.radius;
            this.pointCount = regularPolygon.pointCount ? regularPolygon.pointCount : this.pointCount;
            this.offset = regularPolygon.offset ? regularPolygon.offset : this.offset;
            this.calcPoints();
        }
        if (this.showDebugPolygon) {
            this.showPolygon();
        }

        this.anim && this.addButtonComponent();
    }

    setClickListener(callback:(EventTouch)=>void,target?:any){
        this.target = target ? target : this;
        this.clickListener = callback;
        
    }

    private onClickStart(event: cc.EventTouch) {
        if (!this.clickListener) {
            return;
        }
        this.isMove = false;
        event.propagationStopped = true;
    }
    private onClickMove(event: cc.EventTouch) {
        if (!this.clickListener) {
            return;
        }
        const pos = event.getUILocation();
        const startPos = event.getUIStartLocation();
        const sub = pos.subtract(startPos).length();
        if (sub > 20) {
            this.isMove = true
        }
    }
    private onClickCancel(event: cc.EventTouch) {
        if (!this.clickListener) {
            return;
        }
    }
    private onClickEnd(event: cc.EventTouch) {
        if (!this.clickListener) {
            return;
        }
        event.propagationStopped = true;
        if (!this.isMove) {
            if (this.checkClickAble && !C.getT(event).isOk) {
                //按钮点击过快
                return;
            }
            this.clickListener.bind(this.target)(event);

        }
        this.onClickCancel(event);
    }

    private _hitTest(location: cc.Vec2) {
        if (!this.checkBtnPolygonCollider(location)) {
            return false;
        }
        return this._originalHitTest(location, this.node);
    }

    /**
     * 检查按钮点击是否在多边形内
     * @param ev 点击事件
     */
    private checkBtnPolygonCollider(location: cc.Vec2) {
        if (this.points.length < 3) {
            return true;
        }

        // 获取屏幕坐标
        const screenPos = cc.v3(location.x, location.y, 0);
        const worldPos = cc.v3();
        let canvas = cc.find("Canvas").getComponent(cc.Canvas);
        // 获取 Canvas 关联相机的相机数据
        const uiCamera= canvas.cameraComponent?.camera!;
        // 利用相机数据对象将屏幕点转换成世界坐标下的值
        uiCamera.screenToWorld(worldPos, screenPos);

        let nodePos = this.uiTrans.convertToNodeSpaceAR(cc.v3(worldPos.x, worldPos.y));
        let bHit = GeometryUtils.pointInPolygon(cc.v2(nodePos.x, nodePos.y), this.points);
        return bHit;
    }

    /**计算正多边形顶点坐标 */
    calcPoints() {
        this.points = [];
        for (let i = 0; i < this.pointCount; i++) {
            const x = this.offset.x + this.radius * Math.cos(2 * Math.PI * i / this.pointCount);
            const y = this.offset.y + this.radius * Math.sin(2 * Math.PI * i / this.pointCount);
            this.points[i] = cc.v2(x, y);
        }
    }

    /**绘制多边形 */
    showPolygon(lineWidth: number = 2, strokeColor: cc.Color = cc.Color.RED, fill: boolean = true, fillColor = cc.color(0xff, 0, 0, 50)) {
        let node = this.node;
        let chNode = node.getChildByName(PolygonButtonDebugNode)
        //单独加一个调试节点,用于显示一些额外信息.
        if (chNode == null) {
            chNode = new cc.Node(PolygonButtonDebugNode)
            chNode.setParent(node);
            chNode.layer = node.layer;
            chNode.setSiblingIndex(10000);
        }

        let chTrans = chNode.getComponent(cc.UITransform) || chNode.addComponent(cc.UITransform);
        let nodeTrans = node.getComponent(cc.UITransform);
        chTrans.width = nodeTrans.width
        chTrans.height = nodeTrans.height
        chTrans.setAnchorPoint(nodeTrans.anchorPoint)
        chNode.setPosition(0, 0)

        let g = chNode.getComponent(cc.Graphics) || chNode.addComponent(cc.Graphics);

        g.clear();
        g.lineWidth = lineWidth;
        g.strokeColor = strokeColor
        g.fillColor = fillColor
        let firstPos = this.points[0]
        g.moveTo(firstPos.x, firstPos.y);
        for (let i = 1; i < this.points.length; i++) {
            const pos = this.points[i]
            g.lineTo(pos.x, pos.y);
        }
        g.lineTo(firstPos.x, firstPos.y);
        g.moveTo(firstPos.x, firstPos.y);
        if (fill) {
            g.fill()
        }
        g.stroke()
    }

    /**清除绘制多边形渲染 */
    clearPolygonShow() {
        let chNode = this.node.getChildByName(PolygonButtonDebugNode)
        if (chNode != null) {
            chNode.destroy();
        }
    }

    addButtonComponent(){
        let button = this.node.getComponent<cc.Button>(cc.Button);
        if (!button) {
            button = this.node.addComponent<cc.Button>(cc.Button);
            button.transition = cc.Button.Transition.SCALE;
            button.zoomScale = 0.9;
            button.duration = 0.1;
            button.interactable = true;
        }
    }

}